package com.inno.subject;

import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.util.IdUtil;
import com.inno.auth.api.UserFeignService;
import com.inno.lock.processor.utils.LockApplicationContext;
import com.inno.oss.api.OssFeignService;
import com.inno.subject.domain.feign.FeignProperties;
import com.inno.subject.domain.utils.ApplicationContextUtil;
import com.inno.subject.infra.basic.entity.PlannerSubjectInfo;
import com.inno.subject.infra.basic.service.PlannerSubjectInfoService;
import jakarta.annotation.Resource;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.socket.config.annotation.EnableWebSocket;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Random;
import java.util.concurrent.CompletableFuture;

/**
 * @author sean
 */
@SpringBootApplication
@ComponentScan(basePackages = {"com.inno.subject.**","com.inno.lock.**"})
@MapperScan("com.inno.subject.infra.basic.mapper")
@EnableFeignClients(clients = {UserFeignService.class, OssFeignService.class})
@EnableWebSocket
@RestController
@EnableConfigurationProperties(FeignProperties.class)
public class SubjectApplication {
    public static void main(String[] args) {
        ConfigurableApplicationContext context = SpringApplication.run(SubjectApplication.class, args);
        ApplicationContextUtil.setApplicationContext(context);
        LockApplicationContext.setApplicationContext(context);
    }

    @Resource
    private PlannerSubjectInfoService plannerSubjectInfoService;
    @Resource
    private ThreadPoolTaskExecutor subjectExecutor;
    @GetMapping("/test")
    public void test() {
        Random random = new Random();
        List<PlannerSubjectInfo> infoList = new ArrayList<>();
        for (int i = 0; i < 200000; i++) {
            PlannerSubjectInfo info = new PlannerSubjectInfo();
            info.setId(IdUtil.getSnowflakeNextId());
            // 设置题目分类id，范围为1 - 14，对应你之前给定的分类
            info.setCategoryId((long) (random.nextInt(14) + 1));
            // 设置题目类型id为1（表示简答题）
            info.setSubjectType(1L);
            // 随机生成题目难度等级，0 - 4分别对应不同难度等级
            int level = random.nextInt(5);
            info.setSubjectLevel(String.valueOf(level));
            // 设置是否删除为1（表示未删除）
            info.setIsDeleted("1");
            // 设置创建人、修改人等，这里简单示例设为1，你可根据实际修改
            info.setCreateBy(1L);
            info.setUpdateBy(1L);
            // 设置创建时间、修改时间为当前时间，获取当前时间示例（你可根据实际需求调整日期格式等）
            Date now = new Date();
            info.setCreateTime(now);
            info.setUpdateTime(now);

            // 根据不同分类设置题目名称、题目解析、题目答案
            if (info.getCategoryId() == 1) {
                info.setSubjectName("简述后端开发中接口安全的常用保障措施有哪些？" + i);
                info.setSubjectParse("接口安全保障措施涉及多个方面，比如身份认证可确认请求来源合法性，常见通过用户名密码、Token等方式；授权控制不同用户对接口资源的访问权限，可基于角色等进行分配；加密传输保证数据在网络传输过程中的保密性，像对敏感数据进行对称或非对称加密等；还有防篡改机制，如使用数字签名防止数据被恶意修改等。");
                info.setSubjectAnswer("常用保障措施有身份认证（如使用Token机制）、授权（基于角色分配访问权限）、加密传输（对敏感数据加密）、防篡改（采用数字签名）等。");
            } else if (info.getCategoryId() == 2) {
                info.setSubjectName("Java中线程的几种状态及其转换关系是怎样的？"+ i);
                info.setSubjectParse("Java中线程有新建（New）状态，线程被创建但未启动；就绪（Runnable）状态，线程准备好执行但还未获取到CPU资源；运行（Running）状态，线程获得CPU开始执行；阻塞（Blocked）状态，因等待锁等资源暂停执行；等待（Waiting）状态，等待其他线程通知唤醒；超时等待（Timed Waiting）状态，等待一定时间后自动唤醒；终止（Terminated）状态，线程执行完毕。其转换关系比如新建状态的线程调用start方法进入就绪状态，就绪状态获得CPU进入运行状态等。");
                info.setSubjectAnswer("线程状态有新建、就绪、运行、阻塞、等待、超时等待、终止状态，各状态间依据不同操作如start、获取锁、等待通知等进行转换。");
            } else if (info.getCategoryId() == 3) {
                info.setSubjectName("SpringBoot中如何配置多数据源？"+ i);
                info.setSubjectParse("配置多数据源首先要在项目中引入相应的数据库驱动依赖，然后在配置文件（如application.properties或application.yml）中分别配置不同数据源的连接信息，包括数据库地址、用户名、密码等；接着通过编写配置类，使用@Configuration注解，在类中定义不同的数据源Bean，使用@Primary注解指定主数据源（若有需要），还可以通过@Bean等方式配置数据源相关的事务管理器等组件，确保多数据源能正常使用。");
                info.setSubjectAnswer("引入驱动依赖，配置文件中写连接信息，配置类中定义数据源Bean，指定主数据源，配置事务管理器等组件。");
            } else if (info.getCategoryId() == 4) {
                info.setSubjectName("前端页面布局有哪些常见方式？各自的优缺点是什么？"+ i);
                info.setSubjectParse("常见的有流式布局，优点是简单易实现，能自适应屏幕宽度，缺点是对于复杂的页面结构布局不够精准，元素位置较难精细控制；弹性布局，优点是方便元素根据屏幕尺寸等进行伸缩，适合响应式设计，缺点是在一些老版本浏览器兼容性方面可能存在问题；网格布局，优点是可以精准划分页面区域，方便进行复杂页面布局，缺点是学习成本相对较高，代码结构相对复杂些；还有定位布局，优点是能精确控制元素位置，缺点是脱离文档流后容易造成布局混乱等。");
                info.setSubjectAnswer("常见布局方式有流式、弹性、网格、定位布局等，流式布局简单自适应但难精细控制，弹性布局便于伸缩但兼容性有问题，网格布局精准但学习成本高，定位布局精确控制位置但易布局混乱。");
            } else if (info.getCategoryId() == 5) {
                info.setSubjectName("Vue中如何实现父子组件通信？请举例说明。"+ i);
                info.setSubjectParse("Vue中父子组件通信有多种方式。通过props可以实现父组件向子组件传递数据，例如在父组件的模板中使用子组件标签时，通过绑定属性的方式将数据传递给子组件，子组件通过props选项接收并使用；通过$emit和事件监听可以实现子组件向父组件传递数据，子组件通过$emit触发自定义事件，并传递相应数据，父组件在使用子组件的地方通过v-on指令监听该自定义事件并获取数据，比如在一个计数器组件中，子组件内部计数变化时通过$emit触发事件告知父组件更新显示的值。");
                info.setSubjectAnswer("父子组件通信可通过props（父传子，父组件绑属性传，子组件用props接收）、$emit和事件监听（子传父，子组件触发事件传数据，父组件监听事件获取数据）等方式实现。");
            } else if (info.getCategoryId() == 6) {
                info.setSubjectName("大数据处理中的数据清洗主要步骤有哪些？"+ i);
                info.setSubjectParse("大数据处理中的数据清洗主要步骤包括数据去重，通过特定算法或者数据库的去重功能去除重复的数据记录，避免数据冗余影响后续分析；缺失值处理，根据数据特点和业务需求，可以选择填充缺失值（如用均值、中位数等填充数值型缺失值，用众数填充类别型缺失值）或者直接删除包含缺失值的记录；异常值处理，通过统计方法（如基于标准差等判断离群点）或者业务规则来识别并修正异常值，保证数据的合理性；数据格式统一，将不同格式的数据统一成符合分析要求的格式，比如日期格式统一、字符串编码统一等；数据标准化，将数据进行归一化等操作，使不同量级的数据能在同一尺度下进行比较和分析等。");
                info.setSubjectAnswer("主要步骤有数据去重、缺失值处理（填充或删除）、异常值处理、数据格式统一、数据标准化等。");
            } else if (info.getCategoryId() == 7) {
                info.setSubjectName("Hadoop的核心组件有哪些？它们的作用分别是什么？"+ i);
                info.setSubjectParse("Hadoop的核心组件包括HDFS（分布式文件系统），它负责将大数据文件切分成多个数据块存储在集群中的不同节点上，实现数据的分布式存储，并且具有高容错性，能保证数据的可靠性和可用性；MapReduce（分布式计算框架），用于对存储在HDFS中的海量数据进行并行计算，通过将计算任务分解为Map（映射）和Reduce（归约）两个阶段，高效处理大规模数据，比如进行数据统计、日志分析等任务；YARN（资源管理框架），主要对集群中的计算资源（如CPU、内存等）进行统一管理和分配，协调不同应用程序对资源的需求，使得集群资源能被合理高效利用。");
                info.setSubjectAnswer("核心组件有HDFS（分布式存储数据）、MapReduce（并行计算海量数据）、YARN（管理分配资源），分别负责存储、计算、资源管理。");
            } else if (info.getCategoryId() == 8) {
                info.setSubjectName("Python中如何进行文件操作？请列举常用函数。"+ i);
                info.setSubjectParse("Python中常用的文件操作函数有open打开文件，read读取文件内容，write写入数据到文件，close关闭文件等，还可以使用with语句来自动管理文件资源。");
                info.setSubjectAnswer("常用函数有open打开文件，read读取文件内容，write写入数据到文件，close关闭文件等，还可以使用with语句来自动管理文件资源。");
            } else if (info.getCategoryId() == 9) {
                info.setSubjectName("JavaSE中异常处理的机制是怎样的？"+ i);
                info.setSubjectParse("通过try-catch-finally块来捕获和处理异常，try块中放置可能抛出异常的代码，catch块捕获特定类型异常并处理，finally块中的代码无论是否发生异常都会执行。");
                info.setSubjectAnswer("通过try-catch-finally块来捕获和处理异常，try块中放置可能抛出异常的代码，catch块捕获特定类型异常并处理，finally块中的代码无论是否发生异常都会执行。");
            } else if (info.getCategoryId() == 10) {
                info.setSubjectName("并发编程中线程同步的方法有哪些？请详细阐述。"+ i);
                info.setSubjectParse("有synchronized关键字、Lock接口及其实现类、Semaphore信号量等。synchronized关键字可修饰方法或代码块实现同步；Lock接口提供更灵活的锁定机制；Semaphore可控制同时访问资源的线程数量。");
                info.setSubjectAnswer("有synchronized关键字、Lock接口及其实现类、Semaphore信号量等。synchronized关键字可修饰方法或代码块实现同步；Lock接口提供更灵活的锁定机制；Semaphore可控制同时访问资源的线程数量。");
            } else if (info.getCategoryId() == 11) {
                info.setSubjectName("Java8新特性中Lambda表达式的优势体现在哪些方面？"+ i);
                info.setSubjectParse("代码简洁、可读性强，方便函数式编程，可减少匿名内部类的使用，提高代码的简洁性和可维护性，例如在集合操作、事件处理等场景中使用可使代码更紧凑。");
                info.setSubjectAnswer("代码简洁、可读性强，方便函数式编程，可减少匿名内部类的使用，提高代码的简洁性和可维护性，例如在集合操作、事件处理等场景中使用可使代码更紧凑。");
            } else if (info.getCategoryId() == 12) {
                info.setSubjectName("Java集合框架中List和Set的区别是什么？"+ i);
                info.setSubjectParse("List允许元素重复且有序，可通过索引访问；Set不允许元素重复且无序，主要用于去重和集合运算，如HashSet基于哈希表实现，TreeSet基于红黑树实现有序。");
                info.setSubjectAnswer("List允许元素重复且有序，可通过索引访问；Set不允许元素重复且无序，主要用于去重和集合运算，如HashSet基于哈希表实现，TreeSet基于红黑树实现有序。");
            } else if (info.getCategoryId() == 13) {
                info.setSubjectName("HashMap在Java中的底层数据结构是什么？它是如何解决哈希冲突的？"+ i);
                info.setSubjectParse("底层数据结构是数组 + 链表（或红黑树，在链表长度超过阈值时转换），通过链地址法解决哈希冲突，即相同哈希值的元素存储在同一链表中。");
                info.setSubjectAnswer("底层数据结构是数组 + 链表（或红黑树，在链表长度超过阈值时转换），通过链地址法解决哈希冲突，即相同哈希值的元素存储在同一链表中。");
            } else if (info.getCategoryId() == 14) {
                info.setSubjectName("ConcurrentHashMap是如何保证线程安全的？与HashMap有何不同？"+ i);
                info.setSubjectParse("采用分段锁机制，将数据分成多个段，每个段有独立的锁，不同线程访问不同段数据时可并发执行，相比HashMap，它在多线程环境下能保证线程安全且性能较好。");
                info.setSubjectAnswer("采用分段锁机制，将数据分成多个段，每个段有独立的锁，不同线程访问不同段数据时可并发执行，相比HashMap，它在多线程环境下能保证线程安全且性能较好。");
            }

            // 调用服务层的方法将数据插入数据库，假设服务层有save方法用于插入
            infoList.add(info);
        }
        int batchSize = 10000;
        List<CompletableFuture<Void>> futures = new ArrayList<>();
        for (List<PlannerSubjectInfo> list : ListUtil.partition(infoList, batchSize)) {
            CompletableFuture<Void> future = CompletableFuture.runAsync(() -> plannerSubjectInfoService.batchInsert(list), subjectExecutor);
            futures.add(future);
        }
        CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).join();
        System.out.println("test");
    }
}
